package org.dromara.common.vcp;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.log4j.Log4j2;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.vcp.domain.SzSecret;
import org.dromara.common.vcp.utils.ByteFormat;
import org.dromara.common.vcp.utils.GenReqParam;
import org.dromara.common.vcp.utils.OkHttpUtil;
import org.dromara.common.vcp.utils.XXTea;

import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Log4j2
public class VcpUtil {

    private static final String AI_URL = "https://vcp.21cn.com";

    public static String getLiveUrl(SzSecret szSecret, String params) {
        try {

            int mediaType = 0;
            int proto = 1;
            if (StrUtil.isNotBlank(params)) {
                JSONObject jsonObject = JSONUtil.parseObj(params);
                mediaType = null == jsonObject.get("mediaType") ? mediaType : jsonObject.getInt("mediaType", 0);
                proto = null == jsonObject.get("proto") ? proto : jsonObject.getInt("proto", 1);
            }
            // 接口定义具体入参
            Map<String, Object> map = new HashMap<>();
            map.put("deviceCode", szSecret.getDeviceSn());
            // 直播类型（1.标清；0.高清）
            map.put("mediaType", mediaType);
            // 是否获取https协议的直播地址（0:不支持;1:支持）默认为1
            map.put("supportDomain", 1);

            String url;
            if (SzSecret.API_ONE_VERSION.equals(szSecret.getApiVersion())) {
                url = AI_URL + "/open/u/cloud/getDeviceMediaUrl";
                // 直播地址类型(1.rtsp；3.hls) 默认为 1
                map.put("proto", proto);
            } else {
                if (3 == proto) { // hls
                    url = AI_URL + "/open/token/cloud/getDeviceMediaUrlHls";
                } else { // rtsp
                    url = AI_URL + "/open/token/cloud/getDeviceMediaUrlRtsp";
                }
                // 静音标识（0.非静音;1.静音）
                map.put("mute", 1);
                // 企业主(访问令牌获取方式为“用户无感知获取令牌”，需要传此参数)
                map.put("enterpriseUser", szSecret.getPhone());
                map.put("accessToken", getToken(szSecret));
            }

            String s = sendMessage(url, map, szSecret);
            log.info("摄像头获取流的访问地址：{}, 设备流结果: {}", AI_URL, s);
            JSONObject parse = JSONUtil.parseObj(s);
            if (0 != parse.getInt("code", 1)) {
                log.info("获取结果错误！{}", s);
                return "";
            }
            String data = parse.getStr("data");
            return parseData(data, szSecret);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("设备：【" + szSecret.getDeviceSn() + "】获取视频流失败 ! 原因" + e.getMessage());
        }
    }

    public static JSONArray batchOnlineStatusByCodes(List<SzSecret> secretList) {
        // 同一个密钥分组，避免多个appId多次请求token
        Map<String, List<SzSecret>> appIdList = StreamUtils.groupByKey(secretList, SzSecret::getAppId);
        Map<SzSecret, String> list = new HashMap<>();
        appIdList.forEach((appId, szSecretList) -> list.put(szSecretList.get(0), szSecretList.stream()
                .map(SzSecret::getDeviceSn)
                .collect(Collectors.joining(","))));

        JSONArray jsonArray = new JSONArray();

        list.forEach((szSecret, codes) -> {
            try {
                Map<String, Object> map = new HashMap<>();
                map.put("deviceCodes", codes);

                String url;
                if (SzSecret.API_ONE_VERSION.equals(szSecret.getApiVersion())) {
                    url = AI_URL + "/open/u/device/batchDeviceStatus";
                } else {
                    url = AI_URL + "/open/token/device/batchDeviceStatus";
                    map.put("accessToken", getToken(szSecret));
                }

                String result = sendMessage(url, map, szSecret);
                System.out.println("云眼接口结果：" + result);
                JSONObject jsonObject = JSONUtil.parseObj(result);
                int code = jsonObject.getInt("code", 1);
                if (0 == code) {
                    JSONArray dataList = jsonObject.getJSONArray("data");
                    for (Object object : dataList) {
                        JSONObject json = (JSONObject) object;
                        JSONObject resultMap = new JSONObject();
                        resultMap.set("deviceCode", json.getStr("deviceCode"));
                        resultMap.set("status", json.getStr("status"));
                        jsonArray.add(resultMap);
                    }
                }
            } catch (Exception e) {
                log.error("调用云眼接口：查询设备状态失败！ {}", e.getMessage());
            }

        });

        return jsonArray;
    }

    private static String getToken(SzSecret szSecret) throws Exception {
        String key = GlobalConstants.GLOBAL_REDIS_KEY + "sz:appId:" + szSecret.getAppId();
        if (RedisUtils.hasKey(key)) {
            return RedisUtils.getCacheObject(key);
        }
        Map<String, Object> params = new HashMap<>();
        params.put("grantType", "vcp_189");
        String resultToken = sendMessage(AI_URL + "/open/oauth/getAccessToken", params, szSecret);
        JSONObject json = JSONUtil.parseObj(resultToken);
        if (json.getInt("code", 1) != 0) {
            throw new ServiceException("获取云眼token失败" + resultToken);
        }
        String token = json.getJSONObject("data").getStr("accessToken");
        // 缓存6天 官方说token有效期7天： https://vcp.dlife.cn/portal/document-detail?group=1665564929510465537
        RedisUtils.setCacheObject(key, token, Duration.ofDays(6L));

        return token;
    }


    /**
     * 发送请求
     *
     * @param url url
     * @param map 接口入参
     */
    private static String sendMessage(String url, Map<String, Object> map, SzSecret szSecret) throws Exception {
        Map<String, Object> resultMap = GenReqParam.apiGen(map, szSecret);
        return OkHttpUtil.sendPost(url, resultMap, szSecret.getApiVersion());
    }

    /**
     * 解析视频流地址
     */
    private static String parseData(String data, SzSecret szSecret) throws Exception {
        String decrypt = XXTea.decrypt(data, "UTF-8", ByteFormat.toHex(szSecret.getAppSecret().getBytes()));
        JSONObject parse = JSONUtil.parseObj(decrypt);
        return null == parse.get("url") ? "" : parse.getStr("url");
    }


}
